package com.portal.aspect;

import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONUtil;
import com.portal.annotation.Idempotent;
import com.portal.exception.Assert;
import com.portal.result.impl.BusinessCode;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;

@Aspect     // 切面类
@Component  // 声明为bean组件
public class IdempotentAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    // 切入点表达式，拦截指定的注解
    @Around("@annotation(idempotent)")
    @SneakyThrows
    public Object handler(ProceedingJoinPoint pjp, Idempotent idempotent) {
        // 获取当前执行方法的参数
        Object[] args = pjp.getArgs();
        // 对象转json
        String jsonStr = JSONUtil.toJsonStr(args);
        // MD5加密，保证是唯一标识
        String uniKey = MD5.create().digestHex(jsonStr);
        // redis的setnx命令，实现幂等操作
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(uniKey, 0, idempotent.expire(),idempotent.timeUnit());
        //如果返回true，表示设置成功，如果返回false，表示已经提交过，返回错误
        Assert.error(!ifAbsent, BusinessCode.REPEAT_COMMIT);
        // 放行
        return pjp.proceed();
    }
}
